<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>📊 基本面信息 - 股票选股系统</title>
    <link rel="stylesheet" href="/static/base.css">
    <link rel="stylesheet" href="/static/components.css">
    <link rel="stylesheet" href="/static/pages.css">
    <link rel="stylesheet" href="/static/utilities.css">
    <link rel="stylesheet" href="/static/css/common.css">
    <link href="/static/lib/css/all.min.css" rel="stylesheet">
    <style>
        /* 页面专属微调：进一步压缩关键区域竖向空间 */
        .fundamental-page .panel { padding: 16px; }
        .fundamental-page .market-data-card { padding: 14px 12px; }
        
        /* 确保performance-table样式在fundamental页面正确显示 */
        .fundamental-page .performance-table-container {
            overflow-x: auto;
            border-radius: 8px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
        }
        
        .fundamental-page .performance-table {
            width: 100%;
            border-collapse: collapse;
            background: white;
        }
        
        .fundamental-page .performance-table thead {
            background: #f8f9fa;
            position: sticky;
            top: 0;
            z-index: 10;
        }
        
        .fundamental-page .performance-table th {
            padding: 14px;
            text-align: left;
            font-weight: 600;
            color: #333;
            font-size: 0.9em;
            border-bottom: 2px solid #e9ecef;
            white-space: nowrap;
            background: #f8f9fa;
        }
        
        .fundamental-page .performance-table td {
            padding: 12px 14px;
            border-bottom: 1px solid #e9ecef;
            color: #495057;
            font-weight: normal;
            vertical-align: middle;
        }
        
        .fundamental-page .performance-table tbody tr {
            border-bottom: 1px solid #e9ecef;
            transition: all 0.2s ease;
        }
        
        .fundamental-page .performance-table tbody tr:hover {
            background: #f8f9fa;
        }
        
        .fundamental-page .performance-table tbody tr:last-child td {
            border-bottom: none;
        }
        
        /* 保持原有的涨跌颜色样式 */
        .fundamental-page .performance-table td.positive {
            color: #dc3545;
            font-weight: 600;
        }
        
        .fundamental-page .performance-table td.negative {
            color: #28a745;
            font-weight: 600;
        }
        
        .fundamental-page .performance-table td.positive i {
            color: #dc3545;
        }
        
        .fundamental-page .performance-table td.negative i {
            color: #28a745;
        }
        
        .fundamental-page .performance-table td i {
            margin-right: 4px;
        }
        
        /* 股票代码样式 */
        .fundamental-page .performance-table .code-cell {
            font-weight: 600;
            color: #2c3e50;
            position: relative;
        }
        
        /* 标签样式 */
        .fundamental-page .performance-table .tag {
            display: inline-block;
            padding: 2px 8px;
            margin: 2px;
            background: #e9ecef;
            color: #495057;
            border-radius: 12px;
            font-size: 0.8em;
            font-weight: 500;
        }
        
        .fundamental-page .performance-table .tag.tag-secondary {
            background: #f8f9fa;
            color: #6c757d;
        }
        
        /* 调整列宽度 */
        .fundamental-page .performance-table th:nth-child(7),
        .fundamental-page .performance-table td:nth-child(7) {
            min-width: 150px; /* 总市值列宽度，调宽以显示更多内容 */
            white-space: nowrap;
        }
        
        /* 成交额颜色样式 */
        .fundamental-page .performance-table .turnover-purple {
            color: #8B5CF6 !important; /* 紫色 - 10亿以上 */
            font-weight: 600;
        }
        
        .fundamental-page .performance-table .turnover-blue {
            color: #3B82F6 !important; /* 蓝色 - 5000万到10亿之间 */
            font-weight: 500;
        }
        
        .fundamental-page .performance-table .turnover-black {
            color: #374151 !important; /* 黑色 - 5000万以下 */
        }
        
        /* 股票名称链接样式 */
        .stock-name-link {
            color: #3498db;
            cursor: pointer;
            text-decoration: none;
            transition: color 0.2s ease;
        }
        
        .stock-name-link:hover {
            color: #2980b9;
            text-decoration: underline;
        }
        
        /* K线模态框样式 */
        .kline-modal {
            display: none;
            position: fixed;
            z-index: 1000;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0,0,0,0.5);
        }
        
        .kline-content {
            background-color: white;
            margin: 5% auto;
            padding: 20px;
            border-radius: 8px;
            width: 90%;
            max-width: 1200px;
            max-height: 80vh;
            overflow: auto;
            position: relative;
        }
        
        .kline-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 20px;
            padding-bottom: 10px;
            border-bottom: 1px solid #e9ecef;
        }
        
        .kline-title {
            font-size: 18px;
            font-weight: 600;
            color: #2c3e50;
        }
        
        .close-kline {
            color: #aaa;
            font-size: 28px;
            font-weight: bold;
            cursor: pointer;
            line-height: 1;
        }
        
        .close-kline:hover {
            color: #000;
        }
        
        .kline-container {
            width: 100%;
            height: 500px;
            border: 1px solid #e9ecef;
            border-radius: 4px;
            background: #f8f9fa;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        
        .kline-loading {
            color: #666;
            font-size: 14px;
        }
        
        .kline-error {
            color: #dc3545;
            font-size: 14px;
        }

        /* 名称悬浮小图（迷你K线） */
        .mini-kline-tooltip {
            position: fixed;
            z-index: 2000;
            display: none;
            background: #fff;
            border: 1px solid #e5e7eb;
            box-shadow: 0 4px 16px rgba(0,0,0,0.12);
            border-radius: 6px;
            padding: 8px;
            width: 320px;
            pointer-events: none;
        }
        .mini-kline-title{ font-size: 12px; color:#374151; margin-bottom:6px; }
        .mini-kline-canvas { width: 300px; height: 120px; display:block; }
        
        /* —— 筛选区域样式优化 —— */
        .search-filters-section { margin-top: 0; margin-bottom: 0; }
        .search-filters-container { width: 100%; }
        .search-filters-row { display: flex; flex-wrap: wrap; gap: 1px 1px; align-items: flex-end; margin: 0; }
        .search-filters-section .search-filters-container { padding-top: 0; padding-bottom: 0; }
        .search-panel .filter-group { display: flex; flex-direction: column; gap: 2px; }
        .filter-group .form-control, .filter-group .form-select { min-width: 140px; }
        .filter-group.full-width { flex: 1 1 100%; }
        .input-range { display: inline-flex; align-items: center; gap: 4px; }
        .input-range .form-control { width: 110px; }
        .dropdown-multi .btn { min-width: 140px; }
        @media (max-width: 992px){
            .filter-group .form-control, .filter-group .form-select { min-width: 130px; }
            .input-range .form-control { width: 96px; }
        }
        @media (max-width: 640px){
            .search-filters-row { gap: 6px 10px; }
            .filter-group.full-width .input-group { flex-wrap: wrap; }
        }
        /* 面板与标题区域微缩内边距，压缩垂直空间 */
        .fundamental-page .panel { padding: 12px; }
        .fundamental-panel-header { margin-bottom: 8px; }
    </style>
    
    <script>
        // 简单的 XSS 转义工具
        function escapeHtml(str) {
            if (str === null || str === undefined) return '';
            return String(str)
                .replace(/&/g, '&amp;')
                .replace(/</g, '&lt;')
                .replace(/>/g, '&gt;')
                .replace(/"/g, '&quot;')
                .replace(/'/g, '&#039;');
        }

        // URL 参数读取
        function getUrlParam(name){
            const params = new URLSearchParams(window.location.search);
            return params.get(name);
        }
    </script>
</head>
<body>
    <div class="app-container fundamental-page">
        <div class="header">
            <div class="header-nav">
                <h1><i class="fas fa-chart-bar"></i> 基本面信息</h1>
                <div class="header-nav-links">
                    <!-- 导航将由JavaScript动态生成 -->
                </div>
            </div>
        </div>

        <div class="main-content">
            <div class="tab-content single-panel-layout">
                <div class="results-panel panel">
                    <div class="panel-header fundamental-panel-header">
                        <div class="panel-title"><i class="fas fa-table"></i> 基本面信息</div>
                        <div class="panel-actions">
                            <button id="refreshBtn" class="btn btn-sm btn-secondary"><i class="fas fa-sync-alt"></i> 刷新</button>
                            <button id="exportBtn" class="btn btn-sm btn-primary"><i class="fas fa-download"></i> 导出</button>
                        </div>
                    </div>

                    <div class="results-content">
                        <div class="market-data-cards">
                            <div class="market-data-card"><div class="card-label">总股票数</div><div class="card-value" id="totalStockCount">-</div></div>
                            <div class="market-data-card"><div class="card-label">上涨股票</div><div class="card-value" id="upCount">-</div></div>
                            <div class="market-data-card"><div class="card-label">上涨比例</div><div class="card-value percentage" id="upPercent">-</div></div>
                            <div class="market-data-card"><div class="card-label">平均涨跌幅</div><div class="card-value" id="avgChange">-</div></div>
                            <div class="market-data-card"><div class="card-label">总市值</div><div class="card-value" id="totalMarketValue">-</div></div>
                            <div class="market-data-card"><div class="card-label">最新交易日</div><div class="card-value" id="latestDate">-</div></div>
                        </div>

                        <!-- 第一行：涨跌、仅当日、排序、顺序、每页 -->
                        <div class="search-filters-section">
                            <div class="search-filters-container">
                                <div class="search-filters-row search-panel">
                                    <div class="filter-group">
                                        <label class="filter-label" for="changeFilter">涨跌</label>
                                        <select id="changeFilter" class="form-select form-control">
                                            <option value="">全部</option>
                                            <option value="up">上涨</option>
                                            <option value="down">下跌</option>
                                            <option value="limit_up">涨停</option>
                                            <option value="limit_down">跌停</option>
                                        </select>
                                    </div>
                                    <div class="filter-group">
                                        <label class="filter-label" for="onlyTodayLabels">仅当日打标</label>
                                        <div class="form-check">
                                            <input type="checkbox" id="onlyTodayLabels" class="form-check-input" checked />
                                        </div>
                                    </div>
                                    <div class="filter-group">
                                        <label class="filter-label" for="sortBy">排序字段</label>
                                        <select id="sortBy" class="form-select form-control">
                                            <option value="security_id">证券代码</option>
                                            <option value="security_name">证券名称</option>
                                            <option value="market_value">市值</option>
                                            <option value="change_percent">涨跌幅</option>
                                            <option value="latest_price">最新价</option>
                                            <option value="turnover">成交额</option>
                                        </select>
                                    </div>
                                    <div class="filter-group">
                                        <label class="filter-label" for="sortOrder">顺序</label>
                                        <select id="sortOrder" class="form-select form-control">
                                            <option value="asc">升序</option>
                                            <option value="desc" selected>降序</option>
                                        </select>
                                    </div>
                                    <div class="filter-group">
                                        <label class="filter-label" for="itemsPerPage">每页</label>
                                        <select id="itemsPerPage" class="form-select form-control">
                                            <option value="20">20</option>
                                            <option value="50" selected>50</option>
                                            <option value="100">100</option>
                                        </select>
                                    </div>
                                </div>
                            </div>
                        </div>

                        <!-- 第二行：行业、概念、价格区间、涨跌幅区间 -->
                        <div class="search-filters-section">
                            <div class="search-filters-container">
                                <div class="search-filters-row search-panel">
                                    <div class="filter-group">
                                        <label class="filter-label" for="industryFilter">行业</label>
                                        <div class="dropdown-multi" id="industryDropdown">
                                            <button type="button" id="industryDropdownBtn" class="btn btn-secondary">全部行业</button>
                                            <div class="dropdown-menu" id="industryDropdownMenu"></div>
                                        </div>
                                    </div>
                                    <div class="filter-group">
                                        <label class="filter-label" for="conceptInput">概念包含</label>
                                        <input type="text" id="conceptInput" placeholder="输入概念关键字" class="form-control" />
                                    </div>
                                    <div class="filter-group" style="min-width:280px;">
                                        <label class="filter-label">价格区间（元）</label>
                                        <div class="input-range">
                                            <input type="number" id="priceMin" class="form-control" placeholder="最低" step="0.01" min="0" />
                                            <span style="padding:0 6px;">-</span>
                                            <input type="number" id="priceMax" class="form-control" placeholder="最高" step="0.01" min="0" />
                                        </div>
                                    </div>
                                    <div class="filter-group" style="min-width:300px;">
                                        <label class="filter-label">涨跌幅区间（%）</label>
                                        <div class="input-range">
                                            <input type="number" id="chgMin" class="form-control" placeholder="最低（如 -5）" step="0.01" />
                                            <span style="padding:0 6px;">-</span>
                                            <input type="number" id="chgMax" class="form-control" placeholder="最高（如 10）" step="0.01" />
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>

                        <!-- 第三行：代码/名称搜索 -->
                        <div class="search-filters-section">
                            <div class="search-filters-container">
                                <div class="search-filters-row search-panel">
                                    <div class="filter-group full-width">
                                        <label class="filter-label">股票代码/名称</label>
                                        <div class="input-group">
                                            <input type="text" id="searchInput" placeholder="输入股票代码或名称" class="form-control">
                                            <div class="input-group-append">
                                                <button id="searchBtn" class="btn btn-primary"><i class="fas fa-search"></i> 搜索</button>
                                                <button id="clearBtn" class="btn btn-secondary"><i class="fas fa-eraser"></i> 清除</button>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>

                        <div class="stock-list-container">
                            <div class="list-header">
                                <div class="list-title"><i class="fas fa-list"></i> 基本面信息列表</div>
                                <div class="list-info">显示 <span id="currentRange">0-0</span> 条，共 <span id="totalItems">0</span> 条</div>
                            </div>
                            <div id="fundamentalContainer">
                                <div class="loading" id="loadingIndicator" style="display:none">
                                    <div class="spinner"></div>
                                    <p>加载中...</p>
                                </div>
                            </div>
                            <div id="pagination" class="pagination-container">
                                <div class="pagination">
                                    <button id="prevPage" class="pagination-btn pagination-prev"><i class="fas fa-chevron-left"></i> 上一页</button>
                                    <div class="pagination-pages"></div>
                                    <button id="nextPage" class="pagination-btn pagination-next">下一页 <i class="fas fa-chevron-right"></i></button>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- 悬浮迷你K线容器 -->
    <div id="miniKline" class="mini-kline-tooltip">
        <div class="mini-kline-title" id="miniKlineTitle"></div>
        <canvas id="miniKlineCanvas" class="mini-kline-canvas"></canvas>
    </div>

    <!-- K线模态框 -->
    <div id="klineModal" class="kline-modal">
        <div class="kline-content">
            <div class="kline-header">
                <div class="kline-title" id="klineTitle">K线图</div>
                <span class="close-kline" onclick="closeKline()">&times;</span>
            </div>
            <div class="kline-container" id="klineContainer">
                <div class="kline-loading">加载中...</div>
            </div>
        </div>
    </div>

    <script>
        let allFundamentalData = [];
        let filteredData = [];
        let isLoading = false;
        let currentPage = 1;
        let itemsPerPage = 50;
        let totalPages = 1;
        let apiPage = 1;
        let apiPageSize = 1000;
        let totalApiPages = 1;

        document.addEventListener('DOMContentLoaded', function() {
            // 默认排序字段设为涨跌幅，顺序降序
            const sortBy = document.getElementById('sortBy');
            const sortOrder = document.getElementById('sortOrder');
            if (sortBy) sortBy.value = 'change_percent';
            if (sortOrder) sortOrder.value = 'desc';
            // 应用URL参数到控件
            applyUrlParamsToControls();
            loadFundamentalData();
            bindEvents();
        });

        function bindEvents() {
            const $ = id => document.getElementById(id);
            $('refreshBtn').addEventListener('click', loadFundamentalData);
            $('exportBtn').addEventListener('click', exportData);
            $('searchBtn').addEventListener('click', filterData);
            $('searchInput').addEventListener('keypress', function(e){ if(e.key==='Enter') filterData(); });
            $('clearBtn').addEventListener('click', ()=>{ $('searchInput').value=''; $('conceptInput').value=''; const pm=$('priceMin'),px=$('priceMax'),cm=$('chgMin'),cx=$('chgMax'); if(pm) pm.value=''; if(px) px.value=''; if(cm) cm.value=''; if(cx) cx.value=''; clearIndustrySelection(); filterData(); });
            $('changeFilter').addEventListener('change', filterData);
            const pm=$('priceMin'),px=$('priceMax'),cm=$('chgMin'),cx=$('chgMax');
            if (pm) pm.addEventListener('change', filterData);
            if (px) px.addEventListener('change', filterData);
            if (cm) cm.addEventListener('change', filterData);
            if (cx) cx.addEventListener('change', filterData);
            $('sortBy').addEventListener('change', sortData);
            $('sortOrder').addEventListener('change', sortData);
            $('itemsPerPage').addEventListener('change', function(){ itemsPerPage=parseInt(this.value); currentPage=1; sortData(); });
            $('onlyTodayLabels').addEventListener('change', function(){ currentPage=1; loadFundamentalData(); });
            $('prevPage').addEventListener('click', ()=> goToPage(currentPage-1));
            $('nextPage').addEventListener('click', ()=> goToPage(currentPage+1));
            document.getElementById('conceptInput').addEventListener('input', filterData);
            document.getElementById('industryDropdownBtn').addEventListener('click', toggleIndustryMenu);
            document.addEventListener('click', handleOutsideClickForIndustry);
        }

        function toggleIndustryMenu(e){
            e.stopPropagation();
            const menu = document.getElementById('industryDropdownMenu');
            menu.classList.toggle('open');
        }
        function handleOutsideClickForIndustry(e){
            const wrap = document.getElementById('industryDropdown');
            const menu = document.getElementById('industryDropdownMenu');
            if (!wrap.contains(e.target)) menu.classList.remove('open');
        }

        function updateIndustryButtonLabel(){
            const checked = Array.from(document.querySelectorAll('#industryDropdownMenu input[type="checkbox"]:checked')).map(i=>i.value);
            const btn = document.getElementById('industryDropdownBtn');
            if (!checked.length) btn.textContent = '全部行业';
            else if (checked.length<=2) btn.textContent = checked.join('、');
            else btn.textContent = `已选${checked.length}项`;
        }

        function clearIndustrySelection(){
            document.querySelectorAll('#industryDropdownMenu input[type="checkbox"]').forEach(i=>{ i.checked=false; });
            updateIndustryButtonLabel();
        }

        async function loadFundamentalData() {
            if (isLoading) return;
            isLoading = true; showLoading(true);
            
            // 重置分页
            apiPage = 1;
            allFundamentalData = [];
            
            try {
                await loadFundamentalDataPage();
            } catch (e) {
                console.error(e);
                if (e.name === 'AbortError') {
                    showError('加载基本面数据超时，请稍后重试或减少筛选条件');
                } else if (e.name === 'TypeError' && e.message.includes('fetch')) {
                    showError('网络连接失败，请检查网络连接');
                } else {
                    showError('加载基本面数据失败：' + (e.message || '网络错误'));
                }
            } finally {
                isLoading = false; showLoading(false);
            }
        }
        
        async function loadFundamentalDataPage() {
            const onlyToday = document.getElementById('onlyTodayLabels')?.checked ? '1' : '0';
            const priceMin = document.getElementById('priceMin')?.value || (getUrlParam('price_min')||'');
            const priceMax = document.getElementById('priceMax')?.value || (getUrlParam('price_max')||'');
            const chgMin = document.getElementById('chgMin')?.value || (getUrlParam('chg_min')||'');
            const chgMax = document.getElementById('chgMax')?.value || (getUrlParam('chg_max')||'');
            const params = new URLSearchParams({
                only_today_labels: onlyToday,
                price_min: priceMin,
                price_max: priceMax,
                chg_min: chgMin,
                chg_max: chgMax,
                page: apiPage,
                page_size: apiPageSize
            });
            const indFromUrl = getUrlParam('industry');
            if (indFromUrl) params.set('industry', indFromUrl);
            
            const resp = await fetch('/api/fundamental-data?' + params.toString(), {
                signal: AbortSignal.timeout(30000) // 30秒超时
            });
            const result = await resp.json();
            if (result.success) {
                const pageData = result.data && result.data.fundamental_data ? result.data.fundamental_data : [];
                allFundamentalData = allFundamentalData.concat(pageData);
                
                // 更新分页信息
                totalApiPages = result.data.total_pages || 1;
                
                // 如果还有更多数据，继续加载
                if (apiPage < totalApiPages) {
                    apiPage++;
                    await loadFundamentalDataPage();
                } else {
                    // 所有数据加载完成
                    currentPage = 1;
                    updateStats({ fundamental_data: allFundamentalData, total_count: allFundamentalData.length });
                    populateIndustryOptions();
                    filterData();
                }
            } else {
                showError('加载基本面数据失败：' + (result.error || '未知错误'));
            }
        }

        function applyUrlParamsToControls(){
            const only = getUrlParam('only_today_labels');
            if (only !== null){ const el = document.getElementById('onlyTodayLabels'); if (el) el.checked = (only==='1' || only==='true'); }
            const pm = getUrlParam('price_min'); if (pm!==null){ const el=document.getElementById('priceMin'); if (el) el.value = pm; }
            const px = getUrlParam('price_max'); if (px!==null){ const el=document.getElementById('priceMax'); if (el) el.value = px; }
            const cm = getUrlParam('chg_min'); if (cm!==null){ const el=document.getElementById('chgMin'); if (el) el.value = cm; }
            const cx = getUrlParam('chg_max'); if (cx!==null){ const el=document.getElementById('chgMax'); if (el) el.value = cx; }
        }

        function updateStats(data) {
            const rows = data.fundamental_data || [];
            const totalCount = data.total_count || rows.length || 0;
            const latestDate = data.latest_date || '-';
            document.getElementById('totalStockCount').textContent = totalCount;
            document.getElementById('latestDate').textContent = latestDate;

            if (rows.length) {
                const totalChange = rows.reduce((s, x) => s + (x.change_percent || 0), 0);
                const avgChange = totalChange / rows.length;
                const upCount = rows.filter(x => (x.change_percent || 0) > 0).length;
                const upPercent = (upCount / rows.length * 100).toFixed(1) + '';
                const totalMv = rows.reduce((s, x) => s + (x.market_value || 0), 0);

                document.getElementById('avgChange').textContent = (avgChange>0?'+':'') + avgChange.toFixed(2) + '%';
                document.getElementById('avgChange').className = avgChange>0? 'card-value positive' : avgChange<0? 'card-value negative' : 'card-value';
                document.getElementById('upCount').textContent = upCount;
                document.getElementById('upPercent').textContent = upPercent;
                document.getElementById('totalMarketValue').textContent = formatLargeNumber(totalMv);
            } else {
                document.getElementById('avgChange').textContent = '0.00%';
                document.getElementById('avgChange').className = 'card-value';
                document.getElementById('upCount').textContent = '0';
                document.getElementById('upPercent').textContent = '0.0';
                document.getElementById('totalMarketValue').textContent = '-';
            }
        }

        function formatLargeNumber(num){
            if (!num) return '-';
            if (num >= 100000000) return (num/100000000).toFixed(2) + '亿';
            if (num >= 10000) return (num/10000).toFixed(2) + '万';
            return num.toLocaleString();
        }

        function populateIndustryOptions(){
            const menu = document.getElementById('industryDropdownMenu');
            if (!menu) return;
            const industries = Array.from(new Set((allFundamentalData||[]).map(x=>x.industry).filter(x=>x && x !== '-'))).sort();
            let html = '';
            industries.forEach(ind=>{
                const id = `ind_${encodeURIComponent(ind)}`;
                html += `<label class="dropdown-item"><input type="checkbox" value="${ind}" data-id="${id}" /> <span>${ind}</span></label>`;
            });
            if (!industries.length) html = '<div class="dropdown-empty">无行业数据</div>';
            menu.innerHTML = html;
            menu.querySelectorAll('input[type="checkbox"]').forEach(cb=>{
                cb.addEventListener('change', ()=>{ updateIndustryButtonLabel(); filterData(); });
            });
            updateIndustryButtonLabel();
        }

        function filterData(){
            const term = (document.getElementById('searchInput').value || '').toLowerCase().trim();
            const changeFilter = document.getElementById('changeFilter').value;
            const conceptKey = (document.getElementById('conceptInput').value || '').toLowerCase().trim();
            const selectedIndustries = Array.from(document.querySelectorAll('#industryDropdownMenu input[type="checkbox"]:checked')).map(i=>i.value);
            const priceMin = parseFloat(document.getElementById('priceMin')?.value);
            const priceMax = parseFloat(document.getElementById('priceMax')?.value);
            const chgMin = parseFloat(document.getElementById('chgMin')?.value);
            const chgMax = parseFloat(document.getElementById('chgMax')?.value);

            filteredData = allFundamentalData.filter(item => {
                // 代码/名称筛选
                if (term){
                    const matchCode = item.security_id && item.security_id.toLowerCase().includes(term);
                    const matchName = item.security_name && item.security_name.toLowerCase().includes(term);
                    if (!matchCode && !matchName) return false;
                }
                // 行业多选筛选
                if (selectedIndustries.length>0){
                    if (!item.industry || !selectedIndustries.includes(item.industry)) return false;
                }
                // 概念包含筛选（模糊匹配）
                if (conceptKey){
                    const concepts = (item.concepts || '').toLowerCase();
                    if (!concepts.includes(conceptKey)) return false;
                }
                // 价格范围筛选
                const price = Number(item.latest_price || 0);
                if (!isNaN(priceMin) && price < priceMin) return false;
                if (!isNaN(priceMax) && price > priceMax) return false;
                // 涨跌幅范围筛选
                const cpct = Number(item.change_percent || 0);
                if (!isNaN(chgMin) && cpct < chgMin) return false;
                if (!isNaN(chgMax) && cpct > chgMax) return false;
                // 涨跌方向筛选
                switch (changeFilter){
                    case 'up': return (item.change_percent || 0) > 0;
                    case 'down': return (item.change_percent || 0) < 0;
                    case 'limit_up': return (item.change_percent || 0) >= 9.9;
                    case 'limit_down': return (item.change_percent || 0) <= -9.9;
                    default: return true;
                }
            });
            sortData();
        }

        function sortData(){
            const sortBy = document.getElementById('sortBy').value;
            const sortOrder = document.getElementById('sortOrder').value;
            filteredData.sort((a,b)=>{
                let A,B;
                switch(sortBy){
                    case 'security_id': A=a.security_id||''; B=b.security_id||''; break;
                    case 'security_name': A=a.security_name||''; B=b.security_name||''; break;
                    case 'market_value': A=a.market_value||0; B=b.market_value||0; break;
                    case 'change_percent': A=a.change_percent||0; B=b.change_percent||0; break;
                    case 'latest_price': A=a.latest_price||0; B=b.latest_price||0; break;
                    case 'turnover': A=a.turnover||0; B=b.turnover||0; break;
                    default: A=a.security_id||''; B=b.security_id||'';
                }
                if (typeof A === 'string' && typeof B === 'string'){
                    const r = A.localeCompare(B);
                    return sortOrder==='asc'? r : -r;
                }
                return sortOrder==='asc'? (A-B) : (B-A);
            });

            setupPagination(filteredData);

            const start = (currentPage-1)*itemsPerPage;
            const end = start + itemsPerPage;
            displayFundamentalData(filteredData.slice(start,end));
        }

        function displayFundamentalData(data){
            const container = document.getElementById('fundamentalContainer');
            if (!data || !data.length){
                container.innerHTML = `
                    <div class="empty-state">
                        <i class="fas fa-chart-bar"></i>
                        <div>暂无基本面数据</div>
                        <div>请确认后端接口与数据导入情况</div>
                    </div>
                `;
                return;
            }

            let html = `
                <div class="table-container performance-table-container">
                    <table class="performance-table">
                        <thead>
                            <tr>
                                <th>股票代码</th>
                                <th>股票名称</th>
                                <th>最新价</th>
                                <th>涨跌幅</th>
                                <th>成交量</th>
                                <th>成交额</th>
                                <th>流通市值</th>
                                <th>行业</th>
                                <th>概念</th>
                                <th>标签</th>
                            </tr>
                        </thead>
                        <tbody>
            `;

            data.forEach(item=>{
                const code = item.security_id || '-';
                const name = escapeHtml(item.security_name || '-');
                const lp = Number(item.latest_price||0);
                const cp = Number(item.change_percent||0);
                const vol = item.volume||0;
                const to = item.turnover||0;
                const mv = item.market_value||0;
                const industry = escapeHtml(item.industry || '-');
                const conceptsRaw = item.concepts || '-';
                const concepts = escapeHtml(conceptsRaw);

                const changeClass = cp>=0? 'positive':'negative';
                const changeText = (cp>=0? '+':'') + cp.toFixed(2) + '%';
                const changeAmt = lp - (lp/(1+cp/100));
                const changeAmtText = (changeAmt>=0? '+':'') + changeAmt.toFixed(2);
                const labelsArr = Array.isArray(item.labels)? item.labels : [];
                const labelsTextRaw = labelsArr.length? labelsArr.join(', ') : '';
                const labelsHtml = labelsArr.length? labelsArr.map(l=>`<span class="tag">${escapeHtml(l)}</span>`).join('') : '<span class="tag tag-secondary">无标签</span>';
                const changeIcon = cp>0? '<i class="fas fa-arrow-up"></i>' : cp<0? '<i class="fas fa-arrow-down"></i>' : '<i class="fas fa-minus"></i>';
                
                // 成交额颜色判断（单位：元）
                let turnoverClass = 'turnover-black';
                if (to >= 1000000000) { // 10亿以上（1,000,000,000元）
                    turnoverClass = 'turnover-purple';
                } else if (to >= 50000000) { // 5000万到10亿之间（50,000,000-999,999,999元）
                    turnoverClass = 'turnover-blue';
                }

                html += `
                    <tr>
                        <td class="code-cell">${code}</td>
                        <td><a class="stock-name-link" href="/kline?id=${encodeURIComponent(code)}&name=${encodeURIComponent(name)}" title="点击查看K线图" onmouseenter="handleNameMouseEnter(event, '${code}', '${name}')" onmousemove="handleNameMouseMove(event)" onmouseleave="handleNameMouseLeave()">${name}</a></td>
                        <td>${lp.toFixed(2)}</td>
                        <td class="${changeClass}">${changeIcon} ${changeText}</td>
                        <td>${vol? formatNumber(vol): '-'}</td>
                        <td class="${turnoverClass}">${to? formatNumber(to): '-'}</td>
                        <td>${(mv/100000000).toFixed(2)}亿</td>
                        <td>${industry}</td>
                        <td title="${escapeHtml(conceptsRaw)}">${concepts}</td>
                        <td title="${escapeHtml(labelsTextRaw)}">${labelsHtml}</td>
                    </tr>
                `;
            });

            html += `</tbody></table></div>`;
            container.innerHTML = html;
        }

        function formatNumber(num){
            if (num===null || num===undefined || isNaN(num)) return '-';
            if (Math.abs(num) >= 100000000) return (num/100000000).toFixed(2)+'亿';
            if (Math.abs(num) >= 10000) return (num/10000).toFixed(2)+'万';
            if (Math.abs(num) >= 1000) return (num/1000).toFixed(2)+'K';
            return Number(num).toFixed(2);
        }

        // K线显示功能
        function showKline(code, name) {
            const modal = document.getElementById('klineModal');
            const title = document.getElementById('klineTitle');
            const container = document.getElementById('klineContainer');
            
            // 设置标题
            title.textContent = `${code} ${name} - K线图`;
            
            // 显示模态框
            modal.style.display = 'block';
            
            // 显示加载状态
            container.innerHTML = '<div class="kline-loading">正在加载K线数据...</div>';
            
            // 加载K线数据
            loadKlineData(code, container);
        }
        
        function closeKline() {
            const modal = document.getElementById('klineModal');
            modal.style.display = 'none';
        }
        
        async function loadKlineData(code, container) {
            try {
                // 调用后端API获取K线数据
                const response = await fetch(`/api/stock-kline/${code}`);
                const result = await response.json();
                
                if (result.success) {
                    // 渲染K线图
                    renderKlineChart(result.data.kline_data, container);
                } else {
                    container.innerHTML = `<div class="kline-error">加载失败：${result.error || '未知错误'}</div>`;
                }
            } catch (error) {
                console.error('加载K线数据失败:', error);
                container.innerHTML = `<div class="kline-error">加载失败：${error.message}</div>`;
            }
        }
        
        function renderKlineChart(data, container) {
            // 这里可以集成专业的K线图表库，如ECharts、TradingView等
            // 目前先显示简单的数据表格
            if (!data || data.length === 0) {
                container.innerHTML = '<div class="kline-error">暂无K线数据</div>';
                return;
            }
            
            let html = `
                <div style="width: 100%; height: 100%; overflow: auto;">
                    <table style="width: 100%; border-collapse: collapse; font-size: 12px;">
                        <thead>
                            <tr style="background: #f8f9fa;">
                                <th style="padding: 8px; border: 1px solid #dee2e6; text-align: center;">日期</th>
                                <th style="padding: 8px; border: 1px solid #dee2e6; text-align: right;">开盘</th>
                                <th style="padding: 8px; border: 1px solid #dee2e6; text-align: right;">最高</th>
                                <th style="padding: 8px; border: 1px solid #dee2e6; text-align: right;">最低</th>
                                <th style="padding: 8px; border: 1px solid #dee2e6; text-align: right;">收盘</th>
                                <th style="padding: 8px; border: 1px solid #dee2e6; text-align: right;">成交量</th>
                                <th style="padding: 8px; border: 1px solid #dee2e6; text-align: right;">成交额</th>
                            </tr>
                        </thead>
                        <tbody>
            `;
            
            data.forEach(item => {
                // 计算涨跌幅
                const changePercent = item.change_percent || 0;
                const changeClass = changePercent >= 0 ? 'positive' : 'negative';
                const changeText = (changePercent >= 0 ? '+' : '') + changePercent.toFixed(2) + '%';
                
                html += `
                    <tr>
                        <td style="padding: 8px; border: 1px solid #dee2e6; text-align: center;">${item.date}</td>
                        <td style="padding: 8px; border: 1px solid #dee2e6; text-align: right;">${item.open.toFixed(2)}</td>
                        <td style="padding: 8px; border: 1px solid #dee2e6; text-align: right;">${item.high.toFixed(2)}</td>
                        <td style="padding: 8px; border: 1px solid #dee2e6; text-align: right;">${item.low.toFixed(2)}</td>
                        <td style="padding: 8px; border: 1px solid #dee2e6; text-align: right; color: ${changePercent >= 0 ? '#e53935' : '#2e7d32'};">
                            ${item.close.toFixed(2)} <span style="font-size: 11px;">(${changeText})</span>
                        </td>
                        <td style="padding: 8px; border: 1px solid #dee2e6; text-align: right;">${formatNumber(item.volume)}</td>
                        <td style="padding: 8px; border: 1px solid #dee2e6; text-align: right;">${formatNumber(item.turnover || 0)}</td>
                    </tr>
                `;
            });
            
            html += `
                        </tbody>
                    </table>
                </div>
            `;
            
            container.innerHTML = html;
        }

        // -------- 名称悬浮迷你K线 --------
        let miniKlineCache = {};
        let miniKlineTimer = null;
        function handleNameMouseEnter(e, code, name){
            const tooltip = document.getElementById('miniKline');
            const title = document.getElementById('miniKlineTitle');
            const canvas = document.getElementById('miniKlineCanvas');
            if (!tooltip || !canvas) return;
            title.textContent = `${code} ${name}`;
            tooltip.style.display = 'block';
            positionMiniKline(e);
            // 延迟加载，避免频繁请求
            if (miniKlineTimer) clearTimeout(miniKlineTimer);
            miniKlineTimer = setTimeout(async ()=>{
                const key = code;
                let data = miniKlineCache[key];
                if (!data){
                    try{
                        const resp = await fetch(`/api/stock-kline/${code}?limit=60`);
                        const result = await resp.json();
                        if (result && result.success){
                            data = (result.data && result.data.kline_data) || [];
                            miniKlineCache[key] = data;
                        } else {
                            data = [];
                        }
                    }catch(err){ data = []; }
                }
                drawMiniKline(canvas, data);
            }, 150);
        }
        function handleNameMouseMove(e){ positionMiniKline(e); }
        function handleNameMouseLeave(){
            const tooltip = document.getElementById('miniKline');
            tooltip.style.display = 'none';
            if (miniKlineTimer) { clearTimeout(miniKlineTimer); miniKlineTimer=null; }
        }
        function positionMiniKline(e){
            const tooltip = document.getElementById('miniKline');
            const padding = 12;
            let x = e.clientX + padding;
            let y = e.clientY + padding;
            const rect = tooltip.getBoundingClientRect();
            const vw = window.innerWidth, vh = window.innerHeight;
            if (x + rect.width > vw) x = e.clientX - rect.width - padding;
            if (y + rect.height > vh) y = e.clientY - rect.height - padding;
            tooltip.style.left = x + 'px';
            tooltip.style.top = y + 'px';
        }
        function drawMiniKline(canvas, data){
            const ctx = canvas.getContext('2d');
            const width = canvas.width = 300;
            const height = canvas.height = 120;
            ctx.clearRect(0,0,width,height);
            if (!data || !data.length){
                ctx.fillStyle = '#9CA3AF';
                ctx.font = '12px sans-serif';
                ctx.fillText('暂无数据', 8, 20);
                return;
            }
            // 取收盘价绘制折线
            const closes = data.map(d=> Number(d.close||0));
            const maxV = Math.max(...closes);
            const minV = Math.min(...closes);
            const pad = 8;
            const plotW = width - pad*2;
            const plotH = height - pad*2;
            const n = closes.length;
            // 坐标转换
            const yOf = v => pad + (maxV===minV? plotH/2 : (maxV - v) / (maxV - minV) * plotH);
            const xOf = i => pad + (i/(n-1))*plotW;
            // 网格
            ctx.strokeStyle = '#E5E7EB';
            ctx.lineWidth = 1;
            ctx.beginPath();
            ctx.moveTo(pad, pad);
            ctx.lineTo(pad, height-pad);
            ctx.lineTo(width-pad, height-pad);
            ctx.stroke();
            // 折线
            ctx.strokeStyle = '#2563EB';
            ctx.lineWidth = 1.5;
            ctx.beginPath();
            closes.forEach((v, i)=>{
                const x = xOf(i), y = yOf(v);
                if (i===0) ctx.moveTo(x,y); else ctx.lineTo(x,y);
            });
            ctx.stroke();
            // 阴影填充
            const grad = ctx.createLinearGradient(0, pad, 0, height-pad);
            grad.addColorStop(0, 'rgba(37,99,235,0.25)');
            grad.addColorStop(1, 'rgba(37,99,235,0.02)');
            ctx.fillStyle = grad;
            ctx.lineTo(xOf(n-1), height-pad);
            ctx.lineTo(xOf(0), height-pad);
            ctx.closePath();
            ctx.fill();
        }
        
        // 点击模态框背景关闭
        document.addEventListener('DOMContentLoaded', function() {
            const modal = document.getElementById('klineModal');
            modal.addEventListener('click', function(e) {
                if (e.target === modal) {
                    closeKline();
                }
            });
        });

        function setupPagination(data){
            totalPages = Math.ceil(data.length / itemsPerPage);
            if (currentPage > totalPages) currentPage = totalPages || 1;
            if (currentPage < 1) currentPage = 1;

            const totalItems = data.length;
            const startIndex = (currentPage-1)*itemsPerPage + 1;
            const endIndex = Math.min(startIndex + itemsPerPage - 1, totalItems);
            document.getElementById('currentRange').textContent = `${totalItems? startIndex:0}-${totalItems? endIndex:0}`;
            document.getElementById('totalItems').textContent = totalItems;

            document.getElementById('prevPage').disabled = currentPage<=1;
            document.getElementById('nextPage').disabled = currentPage>=totalPages;

            const pagesContainer = document.querySelector('.pagination-pages');
            let html = '';
            const maxVisible = 5;
            let s=1,e=totalPages;
            if (totalPages>maxVisible){
                const half=Math.floor(maxVisible/2);
                if (currentPage<=half){ s=1; e=maxVisible; }
                else if (currentPage+half>=totalPages){ s=totalPages-maxVisible+1; e=totalPages; }
                else { s=currentPage-half; e=currentPage+half; }
            }
            for (let i=s;i<=e;i++){
                const active = i===currentPage? 'active':'';
                html += `<button class="page-btn ${active}" data-page="${i}">${i}</button>`;
            }
            pagesContainer.innerHTML = html;
            document.querySelectorAll('.page-btn').forEach(btn=>{
                btn.addEventListener('click', ()=> goToPage(parseInt(btn.dataset.page)));
            });
        }

        function goToPage(page){
            if (page<1 || page>totalPages) return;
            currentPage = page;
            const start = (currentPage-1)*itemsPerPage;
            const end = start + itemsPerPage;
            displayFundamentalData(filteredData.slice(start,end));
            setupPagination(filteredData);
            document.querySelector('.results-panel').scrollIntoView({behavior:'smooth'});
        }

        function exportData(){
            if (!allFundamentalData.length){ alert('没有数据可导出'); return; }
            let csv = '证券代码,证券名称,最新价,涨跌幅,涨跌额,成交量,成交额,流通市值(亿),行业,概念,标签\n';
            allFundamentalData.forEach(x=>{
                const lp = Number(x.latest_price||0);
                const cp = Number(x.change_percent||0);
                const changeAmt = lp - (lp/(1+cp/100));
                const labels = x.labels? x.labels.join(';'):'';
                const concepts = x.concepts || '';
                const mvYi = (Number(x.market_value||0)/100000000).toFixed(2);
                
                csv += `"${x.security_id}","${(x.security_name||'').replace(/"/g,'\"')}",${lp.toFixed(2)},${cp.toFixed(2)},${changeAmt.toFixed(2)},${x.volume||0},${x.turnover||0},${mvYi},"${x.industry||''}","${concepts}","${labels}"\n`;
            });
            const blob = new Blob(['\ufeff'+csv], { type:'text/csv;charset=utf-8;' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = `基本面数据_${new Date().toISOString().split('T')[0]}.csv`;
            document.body.appendChild(a); a.click(); document.body.removeChild(a);
            URL.revokeObjectURL(url);
        }

        function showLoading(show){
            const el = document.getElementById('loadingIndicator');
            if (el) el.style.display = show? 'flex':'none';
        }
        function showError(message){
            const container = document.getElementById('fundamentalContainer');
            container.innerHTML = `<div class="alert alert-danger"><i class=\"fas fa-exclamation-triangle\"></i> ${escapeHtml(message)}</div>`;
        }
    </script>
    
    <!-- 公共JavaScript库 -->
    <script src="/static/js/common.js"></script>
    <script src="/static/js/navigation.js"></script>
</body>
</html>


